package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.user.modules.models.Goods;
import cn.wizzer.app.user.modules.models.UserExchange;
import cn.wizzer.app.user.modules.models.UserPurchase;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.PurchaseEnum;
import cn.wizzer.app.user.modules.models.vo.UserPurchaseVO;
import cn.wizzer.app.user.modules.services.GoodsService;
import cn.wizzer.app.user.modules.services.UserPurchaseService;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.commons.lang3.ArrayUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserPurchaseService.class)
public class UserPurchaseServiceImpl extends BaseServiceImpl<UserPurchase> implements UserPurchaseService {

    public UserPurchaseServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;

    @Inject
    @Reference
    private GoodsService goodsService;

    @Inject
    @Reference
    private UserAccountRecordService userAccountRecordService;

    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, String searchKeyword, String[] searchDate, PurchaseEnum status) {
        Sql sql = Sqls.create("SELECT g.name,g.coverPic,p.remark,p.price,p.id,p.status,p.delFlag,p.opAt,p.ctAt,a.receiverName,a.receiverPhone,a.address " +
                "FROM user_purchase AS p " +
                "LEFT JOIN user_address AS a ON p.addressId = a.id " +
                "LEFT JOIN goods g on p.goodsId = g.id " +
                "$condition ");
        Sql countSql = Sqls.create("select count(1) from user_purchase AS p " +
                "$condition ");
        Cnd cnd = Cnd.where("p.delFlag", "=", 0);
        if (status != null) {
            cnd.and("p.status", "=", status);
        }
        if (Strings.isNotBlank(searchKeyword)) {
            searchKeyword = "%" + searchKeyword + "%";
            cnd.and(Cnd.exps("p.receiverName", "like", searchKeyword)
                    .or("p.receiverPhone", "like", searchKeyword));
        }
        if (ArrayUtils.isNotEmpty(searchDate)) {
            cnd.and("p.ctAt", ">=", Times.d2TS(Times.D(searchDate[0])));
            cnd.and("p.ctAt", "<=", Times.d2TS(Times.D(searchDate[1])));
        }
        sql.setCondition(cnd);
        sql.appendSourceSql("order by p.ctAt desc");
        countSql.setCondition(cnd);
        return dbService.listPage(UserPurchaseVO.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, PurchaseEnum status, String userId) {
        Sql sql = Sqls.create("SELECT g.name,g.coverPic,p.id,p.userId,p.remark,p.price,p.status,p.opAt,p.logisticsNo,p.logisticsCompany,p.orderNo " +
                "FROM user_purchase AS p " +
                "LEFT JOIN goods AS g on p.goodsId = g.id " +
                "$condition ");
        Sql countSql = Sqls.create("select count(1) from user_purchase AS p " +
                "$condition ");
        Cnd cnd = Cnd.where("p.userId", "=", userId)
                .and("p.delFlag", "=", 0);
        if (status != null) {
            cnd.and("p.status", "=", status);
        }
        sql.setCondition(cnd);
        sql.appendSourceSql("order by p.opAt desc");
        countSql.setCondition(cnd);
        return dbService.listPage(UserPurchaseVO.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void add(UserPurchase userPurchase) {
        // 查询商品价格
        Goods goods = goodsService.fetch(userPurchase.getGoodsId());
        userPurchase.setPrice(goods.getPrice());
        // 设置订单状态为已付款。余额不足会回滚，不会插入。
        userPurchase.setStatus(PurchaseEnum.PAID);
        // 设置订单创建时间
        userPurchase.setCtAt(Times.getTS());
        //设置订单号
        userPurchase.setOrderNo(Id.createOrderNo());
        // 校验上架状态
        if (goods.isDisabled()) {
            Result.breakWith("商品已经下架");
        }
        // 目前下单时数量不可选，数量都是1。所以校验库存是否小于1.
        if (goods.getStock() < 1) {
            Result.breakWith("库存不足");
        }
        // 更新库存数量
        goods.setStock(goods.getStock() - 1);
        // 乐观锁
        goodsService.updateWithVersion(goods);

        this.insert(userPurchase);
        userAccountRecordService.add("default", userPurchase.getUserId(), userPurchase.getPrice(), BizTypeEnum.PURCHASE, userPurchase.getId(), userPurchase.getOrderNo());

    }

    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void cancel(String id) {
        UserPurchase userPurchase = this.fetch(id);
        if (userPurchase.getStatus() == PurchaseEnum.CANCELED) {
            Result.breakWith("该订单已取消");
        }
        //订单状态
        this.update(Chain.make("status", PurchaseEnum.CANCELED), Cnd.where("id", "=", id));
        //库存
        Goods good = goodsService.fetch(userPurchase.getGoodsId());
        good.setStock(good.getStock() + 1);
        goodsService.updateWithVersion(good);
        //余额
        this.userAccountRecordService.add("default", userPurchase.getUserId(), userPurchase.getPrice(), BizTypeEnum.PURCHASE_BACK, userPurchase.getId(), userPurchase.getOrderNo());
    }
}
